﻿using EmitMapper;
using EmitMapper.Mappers;
using EmitMapper.MappingConfiguration;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PoJun.Tools.Converter
{
    /// <summary>
    /// 实体转换补助类
    /// </summary>
    public static class ModelConverterHelper
    {
        private static ConcurrentDictionary<string, ObjectsMapperBaseImpl> _dictMapping = new ConcurrentDictionary<string, ObjectsMapperBaseImpl>();

        /// <summary>
        /// object转换
        /// </summary>
        /// <typeparam name="TIn"></typeparam>
        /// <typeparam name="TOut"></typeparam>
        /// <param name="inData"></param>
        /// <returns></returns>
        public static TOut ConvertObject<TIn, TOut>(TIn inData)
        {
            Type tin = typeof(TIn);
            Type tout = typeof(TOut);

            string typeKey = string.Concat(tin, "|", tout);
            ObjectsMapperBaseImpl mapperBase = null;
            ObjectsMapper<TIn, TOut> mapper = null;

            mapperBase = _dictMapping.GetOrAdd(typeKey, x =>
            {
                mapper = ObjectMapperManager.DefaultInstance.GetMapper<TIn, TOut>();
                return mapper.MapperImpl;
            });

            if (mapper == null)
            {
                mapper = new ObjectsMapper<TIn, TOut>(mapperBase);
            }

            return mapper.Map(inData);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="tin"></param>
        /// <param name="tout"></param>
        /// <param name="inData"></param>
        /// <returns></returns>
        public static object ConvertObject(Type tin, Type tout, object inData)
        {
            string typeKey = string.Concat(tin, "|", tout);
            ObjectsMapperBaseImpl mapperBase = null;

            mapperBase = _dictMapping.GetOrAdd(typeKey, x =>
            {
                return ObjectMapperManager.DefaultInstance.GetMapperImpl(tin, tout, (IMappingConfigurator)DefaultMapConfig.Instance);
            });

            return mapperBase.Map(inData);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TIn"></typeparam>
        /// <typeparam name="TOut"></typeparam>
        /// <param name="config"></param>
        public static void Register<TIn, TOut>(IMappingConfigurator config = null)
        {
            Type tin = typeof(TIn);
            Type tout = typeof(TOut);
            string typeKey = string.Concat(tin, "|", tout);
            ObjectsMapper<TIn, TOut> mapper = null;
            if (config == null)
            {
                mapper = ObjectMapperManager.DefaultInstance.GetMapper<TIn, TOut>();
            }
            else
            {
                mapper = ObjectMapperManager.DefaultInstance.GetMapper<TIn, TOut>(config);
            }

            _dictMapping.AddOrUpdate(typeKey, mapper.MapperImpl, (_, add) => mapper.MapperImpl);
        }
    }
}
